/*************************************************

@Copyright: inovance
@Author: Caozepeng 10034138
@File: DataBaseManager.h
@Date: 2025-05-30
@Description: 实现数据模型的操作
**************************************************/
#pragma once

#include <sqlite_orm/sqlite_orm.h>

#include <filesystem>
#include <iostream>
#include <memory>
#include <string>
#include <type_traits>

#include "logger.hpp"
#include "storageManager.hpp"

namespace fs = std::filesystem;

// 通用数据库操作模板库
namespace InoIDE {

// 添加PathAndTable和InoId类型定义
using PathAndTable = std::tuple<std::string, std::string>;
using InoId = int64_t;

// 主键类型检测
template <typename T, typename = void>
struct has_id_member : std::false_type {};

template <typename T>
struct has_id_member<T, std::void_t<decltype(std::declval<T>().id)>>
    : std::true_type {};

/// 检查Mode是否有静态string成员tableName
template <typename T, typename = void>
struct has_static_string_tableName_member : std::false_type {};

template <typename T>
struct has_static_string_tableName_member<
    T, std::void_t<decltype(T::tableName),
                   std::enable_if_t<std::is_same_v<
                       std::remove_cv_t<decltype(T::tableName)>, std::string>>>>
    : std::true_type {};

template <typename T>
inline constexpr bool has_static_string_tableName_member_v =
    has_static_string_tableName_member<T>::value;

// 通用数据库操作类
// 模板约束:被操作的对象一定要有id字段
// 通用数据库操作类
template <typename Model,                   // 模型类型
          typename TableMaker,              // 表格创建器类型
          typename StorageType = decltype(  // 存储类型
              TableMaker::makeTable(
                  std::declval<const std::filesystem::path &>(),
                  std::declval<const std::string &>()))>
class DbOperations {
   public:
    // --- 约束 TableMaker ---
    // 检查 TableMaker 是否有一个静态成员函数 makeTable
    // 该函数接受 (const std::string&, const std::string&)
    // 并且返回类型可以转换为 Storage
    static_assert(
        std::is_invocable_r_v<
            StorageType,  // 期望的返回类型 (或可转换到此类型)
            decltype(&TableMaker::makeTable),  // 指向静态成员函数的类型
            const std::filesystem::path &,     // 第一个参数类型
            const std::string &                // 第二个参数类型
            >,
        "TableMaker must have a static method 'Storage makeTable(const "
        "std::string& dbPath, const std::string& "
        "tableName)'");

    // 确保 Model 有 id 成员
    static_assert(
        has_id_member<Model>::value,
        "Model must have an 'id' member for default CRUD operations.");

    using ModelPtr = std::shared_ptr<Model>;
    using ModelsVector = std::vector<Model>;
    using OptionalModel = std::optional<Model>;
    using StoragePtr = std::shared_ptr<StorageType>;
    using ModelsVectorSharedPtr = std::vector<ModelPtr>;

    DbOperations(const fs::path &dbPath, const std::string &tableName)
        : dbPath_(dbPath), tableName_(tableName) {
        auto storageKey = generateStorageKey();
        if (!StorageManInstance().hasStorage(storageKey)) {
            createAndRegisterStorage(storageKey);
        }
    }

    DbOperations(const fs::path &dbPath)
        : DbOperations(dbPath, Model::tableName) {}

    // explicit DbOperations(CInoSubProject *subProject,
    //                       const std::string &tableName)
    //     : dbPath_(subProject->getPath()), tableName_(tableName) {
    //     if (subProject == nullptr) {
    //         LOG_ERROR("subProject is nullptr");
    //         throw(std::runtime_error("subProject is nullptr"));
    //     }
    //     auto storageKey = generateStorageKey();
    //     if (!StorageManInstance().hasStorage(storageKey)) {
    //         createAndRegisterStorage(storageKey);
    //     }
    // }

    // explicit DbOperations(CInoSubProject *subProject)
    //     : dbPath_(subProject->getPath()), tableName_(Model::tableName) {
    //     static_assert(has_static_string_tableName_member_v<Model>,
    //                   "Model must have an static 'tableName' member");
    //     if (subProject == nullptr) {
    //         LOG_ERROR("subProject is nullptr");
    //         throw(std::runtime_error("subProject is nullptr"));
    //     }
    // auto storageKey = generateStorageKey();
    // if (!StorageManInstance().hasStorage(storageKey)) {
    //     createAndRegisterStorage(storageKey);
    // }

    inline StoragePtr getStorage() {
        return StorageManInstance().getStorage<StorageType>(
            generateStorageKey());
    }

    inline StoragePtr getStorageManager() {
        return StorageManInstance().getStorage<StorageType>(
            generateStorageKey());
    }

    /// 插入单个记录
    int64_t insert(Model &model) {
        try {
            model.id = getStorage()->insert(model);
            return model.id;
        } catch (const std::exception &e) {
            LOG_INFO("Failed to insert: {}", e.what());
            // 可以在这里添加日志记录
            throw std::runtime_error(std::string("Failed to insert: ") +
                                     e.what());
        }
    }

    /// 批量插入记录
    std::vector<int64_t> batchInsert(ModelsVector &models) {
        std::vector<int64_t> ids;
        ids.reserve(models.size());
        try {
            for (auto &model : models) {
                ids.emplace_back(this->insert(model));
            }
            return ids;
        } catch (const std::exception &e) {
            throw std::runtime_error(std::string("Failed to batch insert: ") +
                                     e.what());
        }
    }

    // 通过ID查询记录
    ModelPtr getById(int id) {
        try {
            auto result = getStorage()->template get_all<Model>(
                sqlite_orm::where(sqlite_orm::c(&Model::id) == id));

            if (result.empty()) {
                return nullptr;
            }
            return std::make_shared<Model>(std::move(result.front()));
        } catch (const std::exception &e) {
            throw std::runtime_error(std::string("Failed to get by id: ") +
                                     e.what());
        }
    }

    // 获取所有记录
    ModelsVectorSharedPtr getAll() {
        try {
            auto resultsFromDb =
                getStorage()->template get_all<Model>();  // std::vector<Model>
            ModelsVectorSharedPtr modelPtrs;
            modelPtrs.reserve(resultsFromDb.size());
            for (auto &modelObj : resultsFromDb) {
                modelPtrs.push_back(
                    std::make_shared<Model>(std::move(modelObj)));
            }
            return modelPtrs;
        } catch (const std::exception &e) {
            throw std::runtime_error(std::string("Failed to get all models: ") +
                                     e.what());
        }
    }

    // 通过ID更新记录
    void updateById(const Model &model) {
        try {
            getStorage()->update(model);
        } catch (const std::exception &e) {
            throw std::runtime_error(std::string("Failed to update: ") +
                                     e.what());
        }
    }

    // 替换记录（如果不存在则插入）
    void replace(const Model &model) {
        try {
            getStorage()->replace(model);
        } catch (const std::exception &e) {
            throw std::runtime_error(std::string("Failed to replace: ") +
                                     e.what());
        }
    }

    // 通过ID删除记录
    void deleteById(int id) {
        try {
            getStorage()->template remove<Model>(id);
        } catch (const std::exception &e) {
            throw std::runtime_error(std::string("Failed to delete by id: ") +
                                     e.what());
        }
    }

    // 批量删除记录
    void batchDelete(const std::vector<Model> &ids) {
        if (ids.empty()) {
            return;
        }
        try {
            getStorage()->template remove<Model>(ids);
        } catch (const std::exception &e) {
            throw std::runtime_error(std::string("Failed to batch delete: ") +
                                     e.what());
        }
    }

    void batchDeleteByIds(std::vector<InoId> &ids) {
        if (ids.empty()) {
            return;
        }
        try {
            for (const auto &id : ids) {
                getStorage()->template remove<Model>(id);
            }
        } catch (const std::exception &e) {
            throw std::runtime_error(std::string("Failed to batch delete: ") +
                                     e.what());
        }
    }

    // 删除所有记录
    void deleteAll() {
        try {
            getStorage()->template remove_all<Model>();
        } catch (const std::exception &e) {
            throw std::runtime_error(std::string("Failed to delete all: ") +
                                     e.what());
        }
    }

    // 使用条件查询记录
    template <typename... Args>
    ModelsVector findWhere(Args &&...args) {
        try {
            return getStorage()->template get_all<Model>(
                sqlite_orm::where(std::forward<Args>(args)...));
        } catch (const std::exception &e) {
            throw std::runtime_error(
                std::string("Failed to find with condition: ") + e.what());
        }
    }

    // 计数
    int count() {
        try {
            return getStorage()->template count<Model>();
        } catch (const std::exception &e) {
            throw std::runtime_error(std::string("Failed to count: ") +
                                     e.what());
        }
    }

    // 条件计数
    template <typename... Args>
    int countWhere(Args &&...args) {
        try {
            return getStorage()->template count<Model>(
                sqlite_orm::where(std::forward<Args>(args)...));
        } catch (const std::exception &e) {
            throw std::runtime_error(
                std::string("Failed to count with condition: ") + e.what());
        }
    }

   private:
    // 生成存储键名
    inline PathAndTable generateStorageKey() {
        return std::make_tuple(dbPath_.string(), tableName_);
    }

    StoragePtr createAndRegisterStorage(const PathAndTable &storageKey) {
        auto createTableFunc = std::bind(
            &TableMaker::makeTable, dbPath_.generic_u8string(), tableName_);
        auto storage = StorageManInstance().createStorage<StorageType>(
            generateStorageKey(), createTableFunc);
        return storage;
    }

   private:
    fs::path dbPath_;
    std::string tableName_;
};

}  // namespace InoIDE

// 工厂函数应当放在 InoIDE 命名空间中
namespace InoIDE {

/// 工厂函数 - 从StorageManager创建DbOperations
template <typename Model, typename TableMaker, typename Storage>
auto makeDbOperations(const fs::path &dbPath, const std::string &tableName) {
    return DbOperations<Model, TableMaker, Storage>(dbPath, tableName);
}

template <typename Model, typename TableMaker>
auto makeDbOperations(const fs::path &dbPath, const std::string &tableName) {
    return DbOperations<Model, TableMaker>(dbPath, tableName);
}

template <typename Model, typename TableMaker>
auto makeDbOperations(const fs::path &dbPath) {
    return DbOperations<Model, TableMaker>(dbPath);
}

// template <typename Model, typename TableMaker>
// auto makeDbOperations(CInoSubProject *subProject,
//                       const std::string &tableName) {
//     return DbOperations<Model, TableMaker>(subProject, tableName);
// }

// template <typename Model, typename TableMaker>
// auto makeDbOperations(CInoSubProject *subProject) {
//     return DbOperations<Model, TableMaker>(subProject);
// }

}  // namespace InoIDE